from django.db import models
import random
import string
from django.db import IntegrityError
# Create your models here.
"""
第一个版本，为开源插件版本，主要核心功能为让用户可以在自己的网站、APP以添加引入JS的方式快速集成聊天助手。
1.关联用户的账户信息以及聊天历史，用户引入时，需填写APPKEY，APPKEY提供生成或注册地址，注册完成，生成嵌入代码，达到引入即可使用。建立聊天窗口。
2.用户通过ollama选择自己的本地模型、ollama服务器地址、模型初始化提示词、身份设定。（V1采用本地模型选择，V2考虑对接外部大模型KEY。）
3.数据库的方式保存用户的历史聊天内容，但不开放，当用户刷新页面后，则会新建聊天。V2考虑 一个key下，多个用户聊天对接方式。
"""


"""
KEY列表
用户注册登录后可自建KEY，KEY记录调用数量。接口请求次数，以及接口权限。
"""


def generate_app_key():
    characters = string.ascii_letters + string.digits
    while True:
        app_key = ''.join(random.choice(characters) for i in range(32))
        if not ChatAppKey.objects.filter(app_key=app_key).exists():
            return app_key


# 所有的模型列表
class OllamaList(models.Model):
    """
    models_name 大模型的名称
    model_details 大模型的详情
    """
    # 关联的用户，使用 Django 的内置 User 模型
    models_name = models.CharField(max_length=256, verbose_name='大模型的名称')
    model_details = models.JSONField(null=True, blank=True, verbose_name="大模型的详情")

    def __str__(self):
        # 返回 ollama_address
        return self.models_name


class ChatAppKey(models.Model):
    """
    关联的用户
    APPKEY
    生成时间
    最后使用时间
    token使用量
    接口名称及接口调用次数,以json存储记录和更新
    """
    # 关联的用户，使用 Django 的内置 User 模型
    create_user = models.CharField(max_length=256, verbose_name='用户ID')
    # APPKEY 字段，唯一且最大长度为 32 位，可根据实际需求调整
    app_key = models.CharField(max_length=32, unique=True, verbose_name='APPKEY',default=generate_app_key)
    # 用户聊天选择的模型
    select_model = models.CharField(max_length=256, null=True, blank=True, verbose_name='用户聊天选择的模型')
    system_model = models.TextField( null=True, blank=True, verbose_name='用户聊天对模型的初始设定')
    # 生成 APPKEY 的时间，自动记录创建时间
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='生成时间')
    # 最后使用 APPKEY 的时间，自动记录更新时间
    last_used_at = models.DateTimeField(auto_now=True, verbose_name='最后使用时间')
    api_get_num = models.JSONField(null=True, blank=True, verbose_name="接口名称及接口调用次数")
    token_get_num = models.IntegerField(verbose_name="token使用量", default=0)

    def save(self, *args, **kwargs):
        max_attempts = 10  # 设置最大尝试次数，避免无限循环
        attempts = 0
        while attempts < max_attempts:
            try:
                if not self.app_key:
                    self.app_key = generate_app_key()
                if not self.select_model:
                    first_model = OllamaList.objects.first()
                    if first_model:
                        self.select_model = first_model.models_name
                super().save(*args, **kwargs)
                break  # 如果保存成功，跳出循环
            except IntegrityError:
                # 如果发生唯一约束冲突，重新生成 APPKEY 并再次尝试保存
                self.app_key = generate_app_key()
                attempts += 1
        else:
            # 如果达到最大尝试次数仍然失败，可以选择抛出异常或进行其他处理
            raise Exception("无法生成唯一的 APPKEY，请稍后再试。")

    def __str__(self):
        # 返回 APPKEY 的字符串表示，方便在管理界面等地方查看
        return self.app_key



"""
KEY关联的用户聊天记录列表
以JSON的形式存储用户聊天记录，需要对每个聊天记录采用一个唯一码进行筛选，该码可以为任何字符，但为了避免一个key会被多次使用到不同的系统，导致对接的用户ID重复，需要新增一个应用字段来区分。
"""


class ChatHistory(models.Model):
    # 关联的 APPKEY，一个 APPKEY 可以有多个聊天记录
    from_app_key = models.CharField(max_length=256, verbose_name='关联的APPKEY')
    # 关联的 USERID，可以为任意字符串
    from_user_id = models.CharField(max_length=256, null=True, blank=True, verbose_name='关联的USERID')
    # 关联的 USERID，可以为任意字符串
    from_app_id = models.CharField(max_length=256, null=True, blank=True, verbose_name='关联的应用标识')
    # 用户聊天选择的模型
    select_model = models.CharField(max_length=256, null=True, blank=True, verbose_name='该聊天记录选择的模型')
    # 对聊天的记录生成
    system_model = models.CharField(max_length=256, null=True, blank=True, verbose_name='用户聊天对模型的初始设定')
    # 用户输入的聊天内容
    chat_title = models.TextField(null=True, blank=True, verbose_name="聊天标题")
    # 模型生成的回复内容
    chat_json = models.JSONField(null=True, blank=True, verbose_name="聊天记录")
    # 聊天记录的创建时间，自动记录创建时间
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='记录创建时间')
    # 最后使用该记录的更新时间，自动记录更新时间
    last_used_at = models.DateTimeField(auto_now=True, verbose_name='最后使用时间')

    def __str__(self):
        # 返回聊天记录的简要描述，包含 APPKEY 和时间戳
        return self.chat_title

